<?php

class perfsonarnc {
	var $dom,$xp,$cfg,$ma,$timeperiods,$mastr,$timestr;

	function perfsonarnc() {
		require("perfsonarnc.cfg.php");
		$this->cfg=$cfg;
		$this->dom=new DomDocument();
			if(!$this->dom->load($this->cfg['xml']))
				die("Could not loead XML file: ".$this->cfg['xml']);
		$this->xp=new domxpath($this->dom); 
		$this->xp->registerNamespace("nc","urn:ietf:params:xml:ns:netconf:base:1.0");
		$this->xp->registerNamespace("pn","http://stager.uninett.no/perfsonarnc/1.0");
			//Load and initialize available MA
			$index=1;
			$this->ma=array();
			foreach($cfg['ma'] as $name=>$class) {
				if(is_file($class)) {				
					require_once($class);
					$this->ma[$index]=new $name;					
					$index++;
				} else {
					die("Error: Could not load MA - $class\n");
				}
			}

	}

	function addAttr($dom,$name,$value) {
		$attr=$dom->createAttribute($name);
		$attr->appendChild($dom->createTextNode($value));
		return $attr;
	}

	function parseXPath($dom,$ma,$xpath) {
		$nodes=$this->xp->query($xpath);
		if(!$nodes)
			throw new Exception("Malformed XPath expression: $xpath");
		foreach($nodes as $n) {			
			$ma->appendChild($dom->importNode($n,true));			
		}
		return true;
	}

	function editconfig($id,$editdom) {		
		//print $editdom->saveXML();
		//Find data source
		$editxp=new domxpath($editdom);
		$editxp->registerNamespace("nc","urn:ietf:params:xml:ns:netconf:base:1.0");
		$editxp->registerNamespace("pn","http://stager.uninett.no/perfsonarnc/1.0");
		$maid=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:ma")->item(0)->textContent;
		$source=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:dataSource")->item(0)->textContent;
		$report=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:report")->item(0)->textContent;
		$type=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:type")->item(0)->textContent;
		$view=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:view")->item(0)->textContent;
		$tmp=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:obsPoints/pn:obsPoint");
		$obspoints=array();
		foreach($tmp as $t)
			$obspoints[]=$t->textContent;			
		if(count($obspoints)==0) {
			$tmp=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:obsPoints/pn:query");
			if($tmp->length>0) {
				$obs=$this->xp->query($tmp->item(0)->textContent);				
				foreach($obs as $o) {
					if($o->nodeName!="id")
						throw new Exception("Observation point ID not found");
					$obspoints[]=$o->textContent;
				}
			}
		}		
		
		$limit=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:limit")->item(0)->textContent;
		$sort=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:sort")->item(0)->textContent;
		$tmp=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:timePeriods/pn:timePeriod");
		$timeperiods=array();
		if($tmp->length>0) {
			foreach($tmp as $t)	    
			  $timeperiods[]=array('resolution'=>$t->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'resolution')->item(0)->textContent,'timestamp'=>$t->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'timestamp')->item(0)->textContent);
		} else {
			$res=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:timePeriods/pn:resolution")->item(0)->textContent;
			$start=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:timePeriods/pn:start")->item(0)->textContent;
			$stop=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:timePeriods/pn:stop")->item(0)->textContent;
			for($t=$start;$t<$stop;$t+=$res)
				$timeperiods[]=array('resolution'=>$res,'timestamp'=>$t);
		}	
		$filter=NULL;
		$dom=new domDocument();
		$reply=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc-reply");
		$dom->appendChild($reply);
		$reply->appendChild($this->addAttr($dom,"message-id",$id));
		
		if(count($obspoints)==0) {
			debug(1,"No observation points found");
			$reply->appendChild($this->addError($dom, "application", "operation-failed", "error", "No observation points found"));
			return $dom;
		}	

		//Check for arguments
		$args=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query/pn:arguments/pn:argument");
		$arguments=array();
		foreach($args as $node) {
			$id=$node->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'id')->item(0)->textContent;
			$value=$node->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'value')->item(0)->textContent;
			$arguments[]=array('id'=>$id,'value'=>$value);
			if(!$this->validateArgument($source,$report,$id,$value)) {
				$reply->appendChild($this->addError($dom, "application", "operation-failed", "error", "Illegal value for argument $id: $value"));
				return $dom;
			}
		}

		try {
		  $dataresolutiontimeperiods=$this->ma[$maid]->getData($source,$timeperiods,$report,$obspoints,$type,$view,$filter,$sort,$limit,$arguments);
		} catch (Exception $e) {
		  $reply->appendChild($this->addError($dom, "application", "operation-failed", "error", $e->getMessage()));
		  return $dom;
		}
		$dataxml="<result xmlns=\"http://stager.uninett.no/perfsonarnc/1.0\">";
		foreach($dataresolutiontimeperiods as $resolution=>$datatimeperiods) {
		  foreach($datatimeperiods as $tid=>$dataobspoints) {
		    $dataxml.="<timePeriod><resolution>$resolution</resolution><timestamp>$tid</timestamp>";
		    if($type=="table" or $type=="singleTable")
		      foreach($dataobspoints as $obs=>$data) {
			$index=0;
			$dataxml.="<obsPoint><id>$obs</id>";
			$dataxml.="<rows>";
			foreach($data as $r) {
			  $dataxml.="<row><index>$index</index>";
			  $index++;
			  foreach($r as $d)
			    $dataxml.="<datum>$d</datum>";
			  $dataxml.="</row>";
			}
			$dataxml.="</rows></obsPoint>";
		      }
		    elseif($type=="singleOverview") {
		      $dataxml.="<rows>";
		      $index=0;
		      foreach($dataobspoints as $index=>$row) {						
			$oid=array_shift($row);						
			$dataxml.="<row><index>".$index++."</index><obsPoint>$oid</obsPoint>";
			foreach($row as $d)
			  $dataxml.="<datum>$d</datum>";
			$dataxml.="</row>";
		      }
		      $dataxml.="</rows>";
		    }
		    $dataxml.="</timePeriod>";
		  }
		}
		$dataxml.="</result>";
		$d=new domdocument();
		$d->loadXML($dataxml);
		$querynode=$editxp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query")->item(0);
		$querynode->appendChild($editdom->importNode($d->firstChild,true));
		
		//Insert node into dom document
		$tmp=$this->xp->query("/nc:data/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries");
		if(!$tmp->item(0))
		  die("Queries node not found, id=$source");
		$queries=$tmp->item(0);
		$queries->appendChild($this->dom->importNode($querynode,true));
		
		$reply->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","ok"));
		return $dom;
	}
	
	private function validateArgument($dbid,$report,$argid,$value) {
		$enums=$this->xp->query("/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:mas/pn:ma/pn:dataSource[pn:id='$dbid']/pn:reportsInfo/pn:reportInfo[pn:id='$report']/pn:arguments/pn:argument[pn:id='$argid']/pn:enumeration/pn:enum");
		
		if($enums->length==0)
			return true;
		foreach($enums as $e)
		if($e->textContent==$value)
			return true;
		return false;
	}

	function get($id,$xpath) {		
		$dom=new domDocument();
		$reply=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc-reply");
		$dom->appendChild($reply);
		$reply->appendChild($this->addAttr($dom,"message-id",$id));
		try {
				$data=$dom->createElement("data");
				$this->parseXPath($dom,$data,$xpath);
		} catch (Exception $e) {
			$reply->appendChild($this->addError($dom,"application","operation failed","error",$e->getMessage()));
			return $dom;
		}

		$reply->appendChild($data);
		return $dom;
	}
	
	private function addError($dom,$type,$tag,$severity,$message) {
		$error=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc-error");
		$error->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","error-type",$type));
		$error->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","error-tag",$tag));
		$error->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","error-severity",$severity));
		$error->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","error-message",$message));
		return $error;
	}

	function hello() {
		return '<?xml version="1.0"?><hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability>
		<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability></capabilities>
		<session-id>'.getmypid().'</session-id></hello>';
	}
}

?>